﻿#pragma once
#include "../df.h"
namespace df
{
#include "deflate.h"
#include "zlib.h"

	class Compress
	{
		z_stream strm;
	public:
		//************************************
		// Method:    Init 初始化,可重复调用以选择不同的压缩算法
		// Returns:   bool 成功与否
		// Parameter: bool IsGzip 是gzip,否则zlib格式
		// Parameter: ErrWrap err
		// Parameter: int level 压缩等级1-9,越大压缩率越高,速度也越慢
		//************************************
		bool Init(bool IsGzip = true, ErrWrap err = nullptr, int level = Z_DEFAULT_COMPRESSION)
		{
			deflateEnd(&strm);

			strm.zalloc = Z_NULL;
			strm.zfree = Z_NULL;
			strm.opaque = Z_NULL;
			//auto ret = deflateInit(&strm, level);
			auto ret = deflateInit2(&strm
				, level
				, Z_DEFLATED
				, IsGzip ? MAX_WBITS + 16 : MAX_WBITS
				, DEF_MEM_LEVEL
				, Z_DEFAULT_STRATEGY
				);
			if (ret != Z_OK){
				DF_ERRLOG(err, ErrCode::compressError, CCa(strm.msg));
				return false;
			}
			return true;
		}


		//************************************
		// Method:    CompressStart 压缩一段数据
		// Returns:   bool
		// Parameter: bool isLast fromBuf是否是最后一个片段
		// Parameter: const void * fromBuf 
		// Parameter: uint32_t fromSize
		// Parameter: void * toBuf 压缩结果输出缓冲区
		// Parameter: uint32_t toSize 输出缓冲区大小,过小的话会多次回调func,最好比fromSize大一点
		// Parameter: _Func func 压缩成功回调:void(int size)或bool(int size) 返回false中断压缩,size:本次解压的长度,
		// Parameter: ErrWrap err
		//************************************
		template<class _Func>
		bool CompressStart(bool isLast,const void * fromBuf, uint32_t fromSize, void * toBuf, uint32_t toSize
			, _Func func
			, ErrWrap err = nullptr)
		{
			strm.avail_in = fromSize;
			strm.next_in = (Byte*)fromBuf;

			do {
				strm.avail_out = toSize;
				strm.next_out = (Byte*)toBuf;

				auto ret = deflate(&strm, isLast ? Z_FINISH : Z_NO_FLUSH);    /* no bad return value */
				if (ret != Z_STREAM_END && ret != Z_OK) {
					DF_ERRLOG(err, ErrCode::compressError, CCa(strm.msg));
					return false;
				}
				auto have = toSize - strm.avail_out;
				if (!df::ExecuteFunctor(func, have)){
					if (err)
					{
						if (!(*err))
							err->Set(ErrCode::manualStop, tcc_("取消压缩"));
					}
					return false;
				}

			} while (strm.avail_out == 0);

			return true;
		}

		Compress()
		{
			strm = { 0 };
		}
		~Compress()
		{
			deflateEnd(&strm);
		}
		DF_DISABLE_COPY_ASSIGN(Compress);
	};



	class UnCompress
	{
		z_stream strm;
	public:
		//************************************
		// Method:    Init 初始化,可以自动识别gzip或者zlib格式
		// Returns:   bool
		// Parameter: ErrWrap err
		//************************************
		bool Init(ErrWrap err = nullptr)
		{
			inflateEnd(&strm);

			strm.zalloc = Z_NULL;
			strm.zfree = Z_NULL;
			strm.opaque = Z_NULL;
			strm.avail_in = 0;
			strm.next_in = Z_NULL;
			auto ret = inflateInit2(&strm
				, MAX_WBITS + 32);//MAX_WBITS + 32自动识别gzip或者zlib格式
			if (ret != Z_OK){
				DF_ERRLOG(err, ErrCode::uncompressError, CCa(strm.msg));
				return false;
			}
			return true;
		}
		UnCompress()
		{
			strm = { 0 };
		}
		~UnCompress()
		{
			inflateEnd(&strm);
		}


		//************************************
		// Method:    UnCompressStart 解压
		// Returns:   bool
		// Parameter: const void * fromBuf
		// Parameter: uint32_t fromSize
		// Parameter: void * toBuf
		// Parameter: uint32_t toSize 输出缓冲区大小,过小的话会多次回调func,最好比fromSize大几倍
		// Parameter: _Func func 回调签名:void(int size)或bool(int size) size:本次解压的长度,返回false中断解压
		// Parameter: ErrWrap err
		//************************************
		template<class _Func>
		bool UnCompressStart(const void * fromBuf, uint32_t fromSize, void * toBuf, uint32_t toSize
			, _Func func
			, ErrWrap err = nullptr)
		{
			strm.avail_in = fromSize;
			strm.next_in = (Byte*)fromBuf;

			do {
				strm.avail_out = toSize;
				strm.next_out = (Byte*)toBuf;

				auto ret = inflate(&strm, Z_NO_FLUSH);
				if (ret != Z_STREAM_END && ret != Z_OK) {
					DF_ERRLOG(err, ErrCode::uncompressError, CCa(strm.msg));
					return false;
				}

				auto have = toSize - strm.avail_out;


				if (!df::ExecuteFunctor(func, have)){
					if (err)
					{
						if (!(*err))
							err->Set(ErrCode::manualStop, tcc_("取消解压"));
					}
					return false;
				}


			} while (strm.avail_out == 0);

			return true;
		}



		//Compress与Uncompress的返回值
		static const int success = Z_OK;
		static const int memoryLack = Z_MEM_ERROR;
		static const int bufferLack = Z_BUF_ERROR;
		static const int dataError = Z_DATA_ERROR;

		DF_DISABLE_COPY_ASSIGN(UnCompress);
	};




	static inline int Compress2zlib(const void * fromBuf, uint32_t fromSize, void * toBuf, uint32_t * toSize)
	{
		return compress((Byte*)toBuf, (uLong*)toSize, (Byte*)fromBuf, (uLong)fromSize);
	}

	static inline int Uncompress(const void * fromBuf, uint32_t fromSize, void * toBuf, uint32_t * toSize)
	{
		return uncompress((Byte*)toBuf, (uLong*)toSize, (Byte*)fromBuf, (uLong)fromSize);
	}

}